Oracle Policy Automation now provides an Interview Portlet that allows you to embed a Web Determinations interview in a portal. For more information, see Customize the Interview Portlet.
If you do not wish to use the out-of-the-box portlet, you can use this tutorial to teach you how to produce a very simple Interview Portlet, designed to provide the end user with a basic set of screens that will allow the completion of a simple Goal Investigation.
Some more complex features such as access control, inter-portlet communication and more advanced Oracle Policy Automation functionality may be touched on, but for the purposes of this tutorial they will not be gone into in any detail. It is assumed that readers of this tutorial are already familiar with their chosen portal and the intricacies of its Portlet API.
In summary, this tutorial should produce a portlet that utilizes the Interview Service to provide the user with the following:
To complete this tutorial, you will need the following:
Throughout this tutorial the aim is to keep things as simple as possible, providing a basic overview of the way the parts of the portlet being created will hang together without going into excessive detail; for example, in the Render the Summary screen section below, we look at a simple Web Service call using proxy classes to retrieve a new Session Token. Unfortunately no web service call is ever guaranteed to succeed and there are numerous errors that may occur when attempting to call the openSession() method.
Between networking errors, web server issues and problems with the requests themselves being malformed or invalid, there are numerous problems that a portlet would be expected to contend with. For brevity, this tutorial will not perform any error handling, but note that for every web service call made there should always be some attempt to at least check that the call was successful (isSuccessful()), and potentially parse the errorList. No return is ever guaranteed.
As shown in the diagram above, there are four main sections (those shown in blue) that this tutorial will focus on implementing. Taking a ground up approach, starting with the proxy classes required to interact with the Oracle Determinations Server, these are as follows:
Apart from a working development environment and a portal instance, one of the most important things to set-up before commencing work is a deployment of the Determinations Server containing your target rulebase.
The Installation Guides that ship with the Runtime Installers do a better job of explaining the process of deploying the Determinations Server to your target Web Server than could ever be accomplished in this tutorial, so it is recommended you refer to them for the relevant information. Remember to make a note of the Determinations Server's URL once it has been deployed, as you will need this in the next few steps to pull out the required WSDL.
In order to facilitate communication with the Interview Service from Java, we are going to be the JAX. To do this, firstly a set of Proxy Classes that represent our web service in Java must be produced, allowing requests to be built and responses processed using Java Objects.
Proxy class generation is something that is almost always done automatically, and a number of different tools exist to produce the required classes from a source WSDL. Depending on the library that you decided to use, the process you go through to generate the proxy classes will be slightly different, but the general theory is the same. For this example JDeveloper and its Create Web Service Proxy wizard will be used to create the Proxy Classes.
The first step is to pick out the URL that will used to access the Interview Service for the deployed rulebase. The Determinations Server itself has a base URL which, when provided with no arguments, will provide a list of all available WSDLs, similar to the one shown below. As you can see, the Determinations Server itself has three WSDLs available, and each deployed rulebase has eight.
From the list of available WSDLs, the WSDL from which the Proxy Classes will be generated, and the one that will be used for the end point, is the standard Interview WSDL. Note that while the specific and generic WSDLs have legacy 10.0 endpoints available, supporting a non-containment based structure, the Interview Service does not; this is due to the Interview Service only having been introduced in the 10.2 release.
Having selected the relevant WSDL (in this case: /determinations-server/interview/soap/ InterviewServiceTest?wsdl), continue with the process of generating the proxy classes through JDeveloper.
The Create Web Service Proxy wizard can be accessed by right clicking on a Project in JDeveloper, selecting New... and navigating to the Web Services category under Business Tier. You may need to go to the All Technologies tab depending on the type of project you are presently developing, but after selecting Web Service Proxy you should be presented with the following wizard:
Like other proxy class generation tools, the wizard expects to be provided with the location of a valid WSDL for the Web Service you are looking to communicate with. In subsequent steps you will need to provide the Interview Service URL discovered above.
JDeveloper will also request that you provide a root package name in which the classes should be generated. Take care at this point to ensure the package can be referenced easily but does not clutter up any existing source trees.
Further steps may be required depending on the nature of your development, with security policies and handler classes being defined in the last two steps of the wizard. For the purposes of this tutorial however, we can go ahead and click Finish once we have specified a package name, leaving JDeveloper to generate the proxy classes and add them to the project ready for consumption.
In order to get a simple JSR 168 Portlet up and running, the only step we really need to take is extending the GenericPortlet abstract class and overriding the Action and Render methods. Generally there is no need to override the Render or doDispatch methods, since ultimately these methods handle the setting of the portlet title and the dispatching of the request to one of the available doView, doEdit or doHelp methods. Overriding the specific methods is faster and neater.
JDeveloper is being used for this tutorial and so we will be running through the Standards-based Create JSR 168 Java Portlet wizard in order to get up and running.
With this in mind, the first step is right click on the project and select New..., navigating to the Portlets category under Web Tier in the subsequent dialog box. Here you should see the option to kick off the Standards-based Create JSR 168 Java Portlet wizard, the first step of which is as follows:
Since we're making a simple View only portlet, all we need is an appropriate Name, Class and Package in which it will be created. Unchecking the Enable users to edit portlet content flag will ensure that there are no additional Edit pages and code snippets created. Clicking Next will auto-fill the Additional Portlet Information page as shown below, filling in details such as the Portlet Title and Display Name and allowing us to go ahead and finish the tutorial.
Whether you choose to use the Create JSR 168 Java Portlet wizard, or another environment's wizard, or hand craft the required code, the end result should be a very basic JSR 168 Portlet that can be deployed and added to a portal server. In the case of the JDeveloper wizard, a JSP page is also created to which the View requests are dispatched. Using JSP or even a more advanced template engine is preferable to attempting to hand craft the portlet's return each time.
The first step in any communication with the Interview Service is the opening of a Session. Without the token provided by OpenSession it won't be possible to make any successful calls to other methods, so the first task upon having a user load a Portlet is to assign them a session.
To do this, create a simple method in the Interview Interface which takes no arguments and returns a String, the Session Token.
As you can see in the simple method above, accessing the Web Service now the proxy classes have been created, is simply a matter of calling the appropriate method and then sorting through the Java Object returned. In this case, a simple OpenSession method call is all that's required and the InterviewSessionId can be extracted from the response immediately.
Now this token has been obtained, it needs a place to be stored so that it can be used by each subsequent request made by the user. By storing the returned token in the PortletSession we have a simple way of tracking sessions on a per-user basis. A simple way to do this is to check for the presence of the token in the PortletSession each time a Render or Action request is received, returning it or making a call to the newly created openSession method if it is not present.
The Summary screen acts as a landing page for all rulebase interactions. Its main purpose is generally to hold a list of Goals which can be investigated and to report on the state of those goals. However, by using the Screens Editor inside Oracle Policy Automation it can be extended to contain additional HTML, conditional links to Documents, and numerous other elements. Due to the potential complexities involved in rendering summary screens, a simple Goal List could be considered an alternative. This tutorial though will instead focus on providing the capability to render basic summary screens, instead of forming its own.
What is needed first then are a number of additional methods in the Interview Interface, capable of supporting the retrieval of the Summary screen. What we are looking to do is send a GetScreen request to the Interview Service, but to do this we first need to locate the Identifier of the summary screen. The ListScreens method returns a list of all the available screens in a rulebase, similar to the following response:
First it is necessary to have a method that will search the above response for a screen where the type attribute equals summary and pull out the id attribute to obtain the Identifier required for the GetScreen request. Following this, a method that accepts an Identifier and returns the screen contained in the response, is all that is required before the rendering phase.
Since we are dispatching to JSP in order to produce the rendered mark-up, it is necessary to make two additions. The first is to attach the Screen object returned, in this case, by the getScreen method to the RenderRequest; this gives the page access to the Screen object and allows it to be parsed in the JSP code that is written.
So far we have:
Up to this point, the focus has mainly been on the in's and out's of working with the Interview Service and associated proxy classes, pausing only briefly to set-up a basic JSR 168 Portlet. In the last section though, the Summary Screen for the rulebase was retrieved, so it now needs to be rendered to the user. The last stage therefore, is parsing this Screen Definition in JSP to produce the desired HTML, XHTML, WML, and so on.
Interview Screens themselves are potentially very complex structures, containing not only 15 different Control types but errors, warnings, property and potentially commentary as well. For the simple interview portlet though, we are only interested in a small subset of those controls, with discussion of the remaining controls in the Advanced Implementation Considerations section.
All controls inherit from a base control type known as the ControlBase, and as such have a set of consistent attributes; of interest to our Simple Portlet are:
Given the above list of Attributes, the following is a list of controls that our Simple Portlet will be capable of rendering:
We now have a list of elements to look for in the screen definition, and since that has been attached to the RenderRequest it is also possible to access that definition in the JSP page. The Summary screen in the example that was retrieved in the last section contains both label and goal controls, so it is important that the dispatched JSP page is able to handle both.
The JSP Skeleton shown above is simply the start of a JSP page, including the appropriate import and taglib statements to give access to the portlet tags. One of these portlet tags is <portlet:defineObjects/>, which establishes three objects for use in portlet JSP pages; renderRequest, renderResponse and portletConfig. You can see use of one of these objects, the renderRequest, at the end of the JSP stub above, where we pull the screen definition out of the renderRequest attributes.
With that screen definition now in scope and available to be used in the JSP page, all that is left to do is to pull out any required screen attributes:
and loop through the list of controls attached to the screen:
By bringing scriptlets into the mix, it is possible to effectively loop through the Control list, checking the type of each control before applying a suitable rendering method. In the above code stub you can also see that we've used the portlet:renderURL tag to create a URL with which to start our interview. At present, clicking that link will merely result in the same screen being displayed again, since our doView or doDispatch methods have no logic to deal with the presence of a goal parameter. In the next section we'll look at what we need to add in order to go through an interview in our portlet.
In the previous section Portlet JSP tags were used to construct a new renderURL with a goal parameter. What this means is that now, when a user clicks on that link, a new doView or doDispatch (depending on code structure) request will be made, with the goal parameter passed to it in the RenderRequest.
By checking for the presence of this goal parameter, it is possible to make a decision as to whether or not the current getScreen request to retrieve the summary screen is enough, or whether it is now necessary to shift into “Interview” mode.
When first called, the Investigate method takes a session token and goal identifier and returns the first screen definition in that goal's investigation. Subsequent calls to the investigate method then, contain the session token, goal identifier and a populated version of the last screen returned. The interview service then takes the data from this populated screen, adding to the rulebase session and returning the next required screen. Once the goal is calculated as known, unknown or uncertain, the summary screen is then returned with the goal value updated.
The above stub shows what would be required to differentiate between requests where a goal was being investigated, and those where just the Summary screen needed to be displayed. By modifying the JSP page we looked at previously, we can also add code to handle rendering a form for data collection. In fact it would be possible in simple cases to use a single JSP page to handle rendering of both the Summary and Interview screens, though this is not generally recommended.
When creating the data collection form though, the question is raised as to where to target the form's action. Where previously we have used JSP to create a renderURL, passing it the goalId as a parameter, and it would be possible to continue this theme in the form's target. The alternative though is to target the form using JSP to create a new actionURL.
A strong argument for this is that by targeting the form at an actionURL we're able to move the form processing code into the processAction method of the portlet, something which is more in line with the intentions of the portlet specification. This would also allow this code to be reused where the portlet container handled other action requests.
Since there is no easy way to pass the screen definition returned by the investigate method from the processAction to the appropriate render method (doView, doDispatch, render) through the Request and Response objects, we instead go back to the Portlet Session, storing the InterviewScreen there alongside our sessionId that we placed previously.
Considering the above issue and with performance in mind, we choose to place our form processing code in the processAction method of our example, targeting the rendered forms using the same actionURL.
With the investigate method expecting a populated screen definition to be returned in order to continue the interview, we are presented with the following choices:
For our example, we are going to use the final option, choosing to store the screen in the PortletSession before the code dispatches to the JSP page, retrieving it from the session when the subsequent form is then submitted. While we need to ensure that the submitted form is actually related to the screen in memory, we'll be using a request to the getScreen method of the interview service to handle retrieving of a screen which is not currently stored in memory.
When the form is submitted to an Action URL the processAction method is called with a list of parameters from the form itself. These parameters contain not only hidden fields we’ve inserting detailing the name of the screen and particular goalId being investigate but also the value of all fields on the form.
Since our form fields are named to correspond with particular attributes on the screen it represents we can confidently use these parameters in the Request object to update to the Screen definition with new CurrentValues. Looping through each control on the screen in turn, we attempt to pull out the value from the parameter list, format it appropriately where required (Dates, Numbers, and so on) and insert it back into the Screen definition.
The method signature above describes the new method in our Interview Interface, designed to handle part of the form processing requirements. When this screen definition has been updated, the method signature shown above that accepts an InterviewScreen parameter can be used to update the session on the Interview Service.
While the example does not handle entity collection screens where multiple instances may be collecting the same attribute, extending the Attribute Id to contain the Instance Id it relates to would be possible.
With this in mind then, the next thing to do is extend our example's processAction method to handle the possibility of a form submission.
Very few rulebases will ever contain a global entity only. Indeed one of the key advantages of using the Determinations Engine is the ability to define, populate and reason with multiple instances of different entities.
To support multiple entity instances then, our portlet must be extended. Whilst the attribute collection is handled automatically, since the Interview Engine itself takes care of producing multiple “instances” of attribute collection screens for entities, the entity instantiation or collection is not. The next thing to do then is extend our portlet to handle Entity Collect screens.
In order to do this it is necessary to first extend the core JSP page to be able to render containment relationship elements. The elements appear on a screen designed to collect entities and contain zero or more entity-instance elements. These entity-instance elements may themselves contain controls which then need to be rendered (allowing the user to collect attribute data at the same time as entering entity instances), but for the purpose of our basic tutorial we will merely render a single label-control for each entity instance.
With the entity collect screen rendered then, the user must be presented with links to add another instance of the entity, or finish collecting instances and continue to the next part of the interview.
These two links, in our basic portlet, will target the actionURL, with parameters inserted into the URL containing instructions for the processAction code to either add another entity instance to the screen or continue with the interview.
Finally then, our processAction code must be updated to handle the creation and production of an entity collect screen. When an entity collect screen is first returned by the Interview Service it is inserted into the Portlet User Session. Further requests by the user to add an additional instance result in this in session screen definition being updated until, when the user clicks the continue link this screen definition is passed to the Investigate method.
In this way, a basic entity collect screen can be produced.
While this tutorial is meant to give an overview of portlet construction there are some more complicated topics that were not covered as part of the basic Portlet we produced.
One of the advantages of using the Interview Service is the plug-in architecture that is shared with Web Determinations. Data adaptors written for the Interview Engine can be deployed to both the Determinations Server and Web Determinations, giving the Interview Service the ability to load and save common sessions.
For a Portlet this means that we don’t have to worry about serializing and saving sessions and can instead make simple LoadSession, SaveSession and ListSession requests to the Interview Service itself, in order to facilitate session storage. What is important though is that some way of linking a session’s identifier to a particular User or Group within the portal be produced, so it may be later loaded from the session store.
Though the portlet given in this tutorial is designed around the Interview Service it is entirely possible that the API will be chosen instead. Though the Interview Interface concept used in the tutorial means that the changeover of calls to the Interview API from the Service need only be done in one location, it is unfortunately not the only change required. The JSP and Portlet all reference the proxy classes in order to read and write the request and response objects from the Interview Service and these references will all need to be changed to utilize the API Classes. Consider the importance then, of deciding your chosen architecture up front to avoid the need for a switch later in the development cycle.
Where a change may be needed or the possibility of needing to use both the Interview Service and API is present, consider extending the functionality of the Interview Interface to completely wrap all the required classes, instead of directly referencing either the API or Proxy classes. In this way only the Interview Interface need be swapped, though the development effort required is increased.
One of the features of Web Determinations not covered by the tutorial is the construction of a Data Review page. This page provides a simple overview of all data that the user has entered into the session, with the possibility of providing links so the user may be directed to the screen in which they entered that data, allowing them the ability to change their answers without completely resetting the session.
The Interview Service provides three methods which would be useful in the construction of a Data Review Screen: